﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace TSComm.Utilities.Datas
{
    static public class ByteHelper
    {
        /// <summary>
        /// 将Bytes数组Copy到另一个数组
        /// </summary>
        /// <param name="src"></param>
        /// <param name="startIndex"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static byte[] CopyBytes(this byte[] src, int startIndex, int length)
        {
            if (length < 1 || src.Length < (startIndex+length))
            {
                return null;
            }
            byte[] dest = new byte[length];
            Array.Copy(src,startIndex,dest,0,length);
            return dest;
        }

        /// <summary>
        /// 将Bytes数组Copy到另一个数组 
        /// </summary>
        /// <param name="src"></param>
        /// <param name="startIndex"></param>
        /// <returns></returns>
        public static byte[] CopyBytes(this byte[] src, int startIndex)
        {
            if (src.Length < (startIndex+1)) 
                return null;
            byte[] dest = new byte[src.Length-startIndex];
            Array.Copy(src,startIndex,dest,0,src.Length-startIndex);
            return dest;
        }


        /// <summary>
        /// 单个字节转化为16进制字符串
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        public static string ToHex(this byte b)
        {
            return b.ToString("X2");
        }

        /// <summary>
        /// 转换成16进制字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToHex(this IEnumerable<byte> bytes)
        {
            var sb = new StringBuilder();
            foreach (byte b in bytes)
            {
                sb.Append(b.ToString("X2"));
            }
            return sb.ToString();
        }

        /// <summary>
        /// 将Bytes转换为Base64形式字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToBase64String(byte[] bytes)
        {
            return Convert.ToBase64String(bytes);  
        }

        /// <summary>
        /// 转换成整型
        /// </summary>
        /// <param name="value"></param>
        /// <param name="startIndex"></param>
        /// <returns></returns>
        public static int ToInt(this byte[] value, int startIndex=0)
        {
            if (value.Length == 2)
            {
                return BitConverter.ToInt16(value, startIndex);
            }else if (value.Length == 1)
            {
                return (int) value[0];
            }
            else
            {
                return BitConverter.ToInt32(value, startIndex);
            }
            
        }

        /// <summary>
        /// 大端字节序(也称网络字节序)
        /// </summary>
        /// <param name="value"></param>
        /// <param name="startIndex"></param>
        /// <returns></returns>
        public static int ToIntH(this byte[] value, int startIndex = 0)
        {
            if (value.Length<= 1)
                return ByteHelper.ToInt(value,startIndex);
            else if (value.Length == 2)
            {
                short tmp1 = ByteHelper.ToShort(value, startIndex);
                return System.Net.IPAddress.HostToNetworkOrder(tmp1);
            }
            else
            {
                int x = ByteHelper.ToInt(value, startIndex);
                return System.Net.IPAddress.HostToNetworkOrder(x); 
            }
        }

        public static short ToShort(this byte[] value, int startIndex=0)
        {
            if (value.Length == 1)
            {
                return (short)value[0];
            }
            else
            {
                return BitConverter.ToInt16(value, startIndex);
            }
        }

        /// <summary>
        ///大端字节序(也称网络字节序) 
        /// </summary>
        /// <param name="value"></param>
        /// <param name="startIndex"></param>
        /// <returns></returns>
        public static short ToShortH(this byte[] value, int startIndex = 0)
        {
            if (value.Length <= 1)
                return ByteHelper.ToShort(value, startIndex);
            else
            {
                short tmp1 = ByteHelper.ToShort(value, startIndex);
                return System.Net.IPAddress.HostToNetworkOrder(tmp1);
            }
        }

        /// <summary>
        /// 转换成64位整型
        /// </summary>
        /// <param name="value"></param>
        /// <param name="startIndex"></param>
        /// <returns></returns>
        public static long ToInt64(this byte[] value, int startIndex=0)
        {
            byte[] destBytes = new byte[8];
            Buffer.BlockCopy(value,0,destBytes,0,value.Length);

            return BitConverter.ToInt64(destBytes, startIndex);
        }

        public static long ToInt64H(this byte[] value, int startIndex = 0)
        {
            long x = ByteHelper.ToInt64(value, startIndex);
            return System.Net.IPAddress.HostToNetworkOrder(x);
        }

        /// <summary>
        /// 转换为指定编码的字符串
        /// </summary>
        /// <param name="data"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string Decode(this byte[] data, Encoding encoding)
        {
            return encoding.GetString(data);
        } 

        /// <summary>
        /// 转换成BSD码字符串表示形式
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToBSDString(this byte[] bytes)
        {
            return BitConverter.ToString(bytes).Replace("-",""); // 转成字符串后，需要将byte与byte之间的-符号去掉
        }

        public static DateTime To_JSTT_Datetime(this byte[] bytes)
        {
            string datetimeStr = BitConverter.ToString(bytes);
            string dateStr = datetimeStr.Substring(0, 8);
            string timeStr = datetimeStr.Substring(9, 2) + ":00:00";
            return Convert.ToDateTime(dateStr + " " + timeStr);
        }


        #region 位运算
        public static bool GetBit(this byte b, int index)
        {
            return (b & (1 << index)) > 0;
        }

        public static byte SetBit(this byte b, int index)
        {
            b |= (byte)(1 << index);
            return b;
        }

        public static byte ClearBit(this byte b, int index)
        {
            b &= (byte)((1 << 8) - 1 - (1 << index));
            return b;
        }

        public static byte ReverseBit(this byte b, int index)
        {
            b ^= (byte)(1 << index);
            return b;
        }
        #endregion

        public static MemoryStream ToMemoryStream(this byte[] data)
        {
            return new MemoryStream(data);
        }



        public static object ConvertByteData(byte[] srcData, string convertToType, int convertTypeLength,int ampFactor=0)
        {
            switch (convertToType)
            {
                case "int":
                    try
                    {
                        if (convertTypeLength <= 2)
                            return Convert.ToInt16(srcData.ToBSDString(), 16) / (ampFactor == 0 ? 1 : ampFactor);
                        else if (convertTypeLength > 4)
                            return Convert.ToInt64(srcData.ToBSDString(), 16) / (ampFactor == 0 ? 1 : ampFactor);
                        else
                            return Convert.ToInt32(srcData.ToBSDString(), 16) / (ampFactor == 0 ? 1 : ampFactor);
                    }
                    catch (Exception e)
                    {
                        return -1; 
                    }
                case "bool":
                    return srcData.ToShortH() > 0 ? 1 : 0; 
                case "nvarchar":
                    return srcData.ToBSDString();
                    //// 对于SIM字符串特别处理
                    //if (retVal.Length == 12 && retVal[0] == '0')
                    //    retVal = retVal.Substring(1, (retVal.Length - 1));
                    break;
                case "numeric":
                    try
                    {
                        if (convertTypeLength <= 2)
                            return (double)(Convert.ToDouble(Convert.ToInt16(srcData.ToBSDString(), 16)) / (ampFactor == 0 ? 1 : ampFactor));
                        else if (convertTypeLength > 4)
                            return (double)(Convert.ToDouble(Convert.ToInt64(srcData.ToBSDString(), 16)) / (ampFactor == 0 ? 1 : ampFactor));
                        else
                            return (double)(Convert.ToDouble(Convert.ToInt32(srcData.ToBSDString(), 16)) / (ampFactor == 0 ? 1 : ampFactor));
                    }
                    catch (Exception e)
                    {
                        return -1;
                    }
                    break;
                //    return (double)(Convert.ToDouble(srcData.ToIntH()) / (ampFactor == 0 ? 1 : ampFactor));
                default:
                    return 0;
            }
            // ON PeriodScheme(JST_DATE)  [numeric](16,3)
            return 0;
        }

        /// <summary>
        /// 对byte按照字节，bit位分割。
        /// 注意，此函数针对字节中的Bit位是从高到低，分别是0-7升序的。
        /// 也就是说，一个字节中，最高位代表0，最低位代表7
        /// 字节：   00000000
        ///         ↑↑↑↑↑↑↑↑↑
        /// 位数：   01234567
        /// </summary>
        /// <param name="datas"></param>
        /// <param name="byteStart"></param>
        /// <param name="byteLength"></param>
        /// <param name="bitStart"></param>
        /// <param name="bitLength"></param>
        /// <returns></returns>
        public static byte[] SplitByteDataHL(byte[] datas, int byteStart, int byteLength, int bitStart, int bitLength)
        {
            if (bitLength <= 0)
            {
                return datas.CopyBytes(byteStart, byteLength);
            }
            else
            {
                if (bitLength > 8)
                    return null;  // 无效
                else
                {
                    // 假设提取一个字节的内容是11010101
                    // bitStart=2, bitLength=3
                    // 那么，最后需要得的内容是010
                    // 以下代码是规则是这样的：
                    //    首先生成模板 00111000,因为只需要从第2位开始，往后取3位的数字
                    //      生成模板的方式：是通过11111111这个数字，先向左移5位(8-3),再向右移2位。
                    //    与原数据内容进行与操作(&)  11010101 & 00111000, 得到00101000
                    //    最后，向右移3位（即8-2-3），得到00000010,就是想要的数据。
                    byte s = datas[byteStart];
                    byte maskByte = 255; //11111111
                    maskByte = (byte)(((byte)maskByte) << (8 - bitLength));
                    maskByte = (byte)(((byte)maskByte) >> (bitStart));
                    s = (byte)(s & maskByte);
                    s = (byte)((byte)s >> (8 - bitLength - bitStart));
                    byte[] sArray = new[] { s };
                    return sArray;
                }
            }
        }


        /// <summary>
        /// 对byte按照字节，bit位分割。
        /// 注意，此函数针对字节中的Bit位是从低到高，分别是7-0降序的。一般计算机就是这个顺序位
        /// 一个字节中，最高位代表7，最低位代表0
        /// 字节：   00000000
        ///         ↑↑↑↑↑↑↑↑↑
        /// 位数：   76543210 
        /// </summary>
        /// <param name="datas"></param>
        /// <param name="byteStart"></param>
        /// <param name="byteLength"></param>
        /// <param name="bitStart"></param>
        /// <param name="bitLength"></param>
        /// <returns></returns>
        public static byte[] SplitByteDataLH(byte[] datas, int byteStart, int byteLength, int bitStart, int bitLength)
        {
           // bitLength不能超过要取得位数的超始位置+1
           // 比如，起始位置为1，那么只bitLength最多有两个长度
            if (bitLength <= 0 || bitLength>(bitStart+1))
            {
                return datas.CopyBytes(byteStart, byteLength);
            }
            else
            {
                if (bitLength > 8) // 无效
                    return datas.CopyBytes(byteStart, byteLength);
                else
                {
                    // 假设提取一个字节的内容是11010101
                    // bitStart=2, bitLength=2
                    // 那么，最后需要得的内容是10，11010(10)1
                    // 以下代码是规则是这样的：
                    //    首先生成模板 00000110,因为只需要从第2位开始，往后取3位的数字
                    //      生成模板的方式：是通过11111111这个数字，先向左移6位(8-bitLength),再向右移5(8-bitStart-1)位。
                    //    与原数据内容进行与操作(&)  11010101 & 00000110,得到00000100 
                    //    最后，向右移1位（即bitStart-bitLength+1），得到00000010,就是想要的数据。
                    byte s = datas[byteStart];
                    byte maskByte = 255; //11111111
                    maskByte = (byte)(((byte)maskByte) << (8 - bitLength));
                    maskByte = (byte)(((byte)maskByte) >> (8-bitStart-1));
                    s = (byte)(s & maskByte);
                    s = (byte)((byte)s >> (bitStart-bitLength+1));
                    byte[] sArray = new[] { s };
                    return sArray;
                }
            }
        }
    }
}
